/*
 * TCSS 360 - Autumn 2011
 * Group2: ManuscriptPR 
 * 
 * UserCollection class
 * Author: Tony Butterfield
 */
package user;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

/**
 * collection of Users plus methods to manage them.
 * 
 * @author Tony Butterfield
 * @version 11/29/2011
 */
public class UserCollection 
{
  // STATIC FIELDS ****************************************
  /** test file token delimiter. */
  private static final String COMMA = ",";  
  
  
  // INSTANCE VARIABLES ***********************************
  /** backing store for the UserCollection. */
  private Map<String, User> my_users;
  
  // CONSTRUCTORS *****************************************
  /**
   * creates a new instance of the UserCollection class.
   */
  public UserCollection()
  {
    my_users = new HashMap<String, User>();
  }
  
  
  // ACCESSORS ********************************************
  /**
   * get User by name.
   * @param the_user_name String to match to User's name
   * @return User whose name matches or null
   ********************************************************
   * @requires the_user_name = String with user name (last, first)
   * @ensures method returns User object matching the_user_name, or null
   */
  public User getUser(final String the_user_name)
  {
    return my_users.get(the_user_name);
  }
  
  
  /**
   * get List of all User names in collection.
   * @return List of sorted User names (last, first)
   ********************************************************
   * @ensures method returns a List<String> with all user names from the collection
   */  
  public List<String> getAllUserNames()
  {
    final List<String> name_list = new ArrayList<String>(my_users.keySet());
    Collections.sort(name_list);
    return name_list;
  }
  
  /**
   * get List of all User names who are members of a conference.
   * @param the_conference_name String containing the name of a Conference
   * @return List of sorted User names (last, first)
   ********************************************************
   * @requires the_conference_name = String
   * @ensures method returns a List<String> with all user names who are members of that 
   *  conference
   */
  public List<String> getConferenceMembers(final String the_conference_name)
  {
    final List<String> name_list = new ArrayList<String>(my_users.keySet());
    final List<String> result_list = new ArrayList<String>();
    
    for (String name : name_list)
    {
      if (getUser(name).isMember(the_conference_name))
      {
        result_list.add(name);
      }
    }
    
    Collections.sort(result_list);
    
    return result_list;
  }
  
  /**
   * get List of names of all conferences that have members in the User collection.
   * @return List of sorted conference names
   ********************************************************
   * @ensures method returns a sorted List<String> with all conference names
   */
  public List<String> getAllConferenceNames()
  {
    final Map<String, String> conference_map = new HashMap<String, String>();    

    for (String user_name : getAllUserNames())
    {
      for (String conference_name : getUser(user_name).getAllConferenceNames())
      {
        conference_map.put(conference_name, null);
      }
    }

    return new ArrayList<String>(conference_map.keySet());
  }
  
  
  /**
   * get a reference to a Conference object of the given name.
   * @param the_conf_name String with name of the conference
   * @return Conference that matches that string of null
   ********************************************************
   * @requires the_conf_name = String
   * @ensures the method returns the first matching Conference object 
   *    in the collection or null
   */
  public Conference getConference(final String the_conf_name)
  {
    final List<String> users = getAllUserNames();
    Conference result = null;
        
    for (String u : users)
    {
      final User user = getUser(u);
      if (user.isMember(the_conf_name))
      {
        result = user.getConference(the_conf_name);
        break;
      }
    }
    
    return result;
  }
  
  public Role getUserRole(final User the_user, final Conference the_conference)
  {
    return the_user.getRole(the_conference);
  }
  
  
  
  // MUTATORS *********************************************
  /**
   * add User to the collection.
   * @param the_user User to be added to the collection.
   * @throws NullPointerException()
   *******************************************************
   * @requires the_user = User
   * @ensures User is added to the Collection
   */
  public void addUser(final User the_user)
  {
    if (the_user != null)
    {
      my_users.put(the_user.getFullName(), the_user);
    }
    else
    {
      throw new NullPointerException();
    }
  }
  

  /**
   * set User Role for a specified conference.
   * @param the_user User to be accessed
   * @param the_conference Conference to be updated.
   * @param the_role Role to be assigned
   * @return boolean success = true, failure = false
   ********************************************************
   * @requires the_user = User
   *           the_conference = Conference
   *           the_role = Role
   * @ensures  if (the_user.getConference(the_conference) != null) then 
   *              the_user.setConferenceRole(Conference, Role) will update the User's role and
   *              return TRUE
   *           else return FALSE
   */
  public boolean setUserRole(final User the_user, final Conference the_conference, 
      final Role the_role)
  {
    the_user.addConferenceRole(the_conference, the_role);
    return true;
  }

  /**
   * set User Role for a specified conference.
   * @param the_user_name String name of User to be accessed
   * @param the_conference Conference to be added/updated.
   * @param the_role Role to be assigned
   * @return boolean success = true, failure = false
   ********************************************************
   * @requires the_user_name = String
   *           the_conference = Conference
   *           the_role = Role
   * @ensures  if (the_user.getConference(the_conference) != null) then 
   *              the_user.setConferenceRole(Conference, Role) will update the User's role and
   *              return TRUE
   *           else return FALSE
   */
  public boolean setUserRole(final String the_user_name, final Conference the_conference, 
      final Role the_role)
  {
    boolean result = false;

    final User user = my_users.get(the_user_name);

    if (user != null)
    {
      user.addConferenceRole(the_conference, the_role);
      result = true;      
    }
    return result;
  }


  // METHODS **********************************************
  /**
   * load all test data.
   * @throws IOException 
   */
  public void loadAllTestData() throws IOException
  {
    final File test_file = new File("user_test.txt");   // file containing initial field values
    
    final BufferedReader reader = new BufferedReader(new FileReader(test_file));
    String line = null;
    
    // get each line (format: FIRSTNAME,LASTNAME,CONFNAME,YEAR,MONTH,DAY,YEAR,MONTH,DAY,ROLE
    // (repeat for each conf)
    while ((line = reader.readLine()) != null)
    {
      final StringTokenizer token = new StringTokenizer(line, COMMA);
      
      final String fname = token.nextToken();
      final String lname = token.nextToken();
      
      final User user = new User(fname, lname);     // not checking for duplicates...
      
      while (token.hasMoreTokens())           // get each conference
      {
        final String conf_name = token.nextToken();
        final int date_yyyy = Integer.parseInt(token.nextToken());
        final int date_mm = Integer.parseInt(token.nextToken());
        final int date_dd = Integer.parseInt(token.nextToken());
        final int dead_yyyy = Integer.parseInt(token.nextToken());
        final int dead_mm = Integer.parseInt(token.nextToken());
        final int dead_dd = Integer.parseInt(token.nextToken());
        
        final Conference conf = new Conference(conf_name, 
            new GregorianCalendar(date_yyyy, date_mm, date_dd), 
            new GregorianCalendar(dead_yyyy, dead_mm, dead_dd));
        
        final Role role = Role.parseString(token.nextToken());
                
        user.addConferenceRole(conf, role);
      }
      
      addUser(user);
    }
  }  
}
